package cn.sunxyz.data.orm;

import cn.sunxyz.common.base.annotation.NotNull;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Created by yangrd on 2017/6/7.
 */
public class IMethod {
    private Class<?> entityClazz;
    private Class<?> targetClazz;
    // This is guaranteed to be interned by the VM in the 1.4
    // reflection implementation
    private String name;
    private Class<?> returnType;
    private Class<?>[] parameterTypes;
    private Class<?>[] exceptionTypes;

    private IMethod(Class<?> entityClazz, Class<?> targetClazz, String name, Class<?> returnType, Class<?>[] parameterTypes, Class<?>[] exceptionTypes) {
        this.entityClazz = entityClazz;
        this.targetClazz = targetClazz;
        this.name = name;
        this.returnType = returnType;
        this.parameterTypes = parameterTypes;
        this.exceptionTypes = exceptionTypes;
    }

    public Class<?> getEntityClazz() {
        return entityClazz;
    }

    public Class<?> getTargetClazz() {
        return targetClazz;
    }

    public String getName() {
        return name;
    }

    public Class<?> getReturnType() {
        return returnType;
    }

    public Class<?>[] getParameterTypes() {
        return parameterTypes;
    }

    public Class<?>[] getExceptionTypes() {
        return exceptionTypes;
    }

    public static class Builder {
        public static IMethod of(@NotNull Method method, @NotNull Class<?> entityCls) {
            return new IMethod(entityCls, getTargetClazz(method), method.getName(), method.getReturnType(), method.getParameterTypes(), method.getExceptionTypes());
        }

        public static IMethod of(@NotNull String name, @NotNull Class<?> returnType, @NotNull Class<?>[] parameterTypes, @NotNull Class<?> entityCls) {
            return new IMethod(entityCls, entityCls, name, returnType, parameterTypes, null);
        }

        private static Class<?> getTargetClazz(Method method) {
            Type genericFieldType = method.getGenericReturnType();
            Class<?> targetClazz = method.getReturnType();
            if (genericFieldType instanceof ParameterizedType) {
                ParameterizedType aType = (ParameterizedType) genericFieldType;
                Type[] fieldArgTypes = aType.getActualTypeArguments();
                targetClazz = (Class<?>) fieldArgTypes[0];
            }
            return targetClazz;
        }
    }


}
